package com.example.factory;

import com.example.transport.ClientTransportService;
import com.exmaple.dto.RpcPing;
import com.exmaple.dto.RpcResponse;
import com.exmaple.dto.RpcRequest;
import com.exmaple.handler.IHandler;
import com.exmaple.utils.IpUtil;
import com.example.utils.SpringUtil;

import java.util.concurrent.*;
import java.util.logging.Logger;

public class SysClientServerFactory extends AbstractServerFactory implements ClientTransportService {

    Logger logger = Logger.getLogger(getClass().getName());

    private volatile Boolean started = Boolean.FALSE;

    private Thread[] pingThreads = null;

    private String baseUrl;

    private int port;

    private int corePoolSize = 5;

    private int maximumPoolSize = 10;

    private long keepAliveTime = 5;

    private ExecutorService executorService = null;

    public SysClientServerFactory(String baseUrl, int port) {
        this.baseUrl = baseUrl;
        this.port = port;
    }

    @Override
    public void init() {
        this.executorService = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, new LinkedBlockingDeque());
    }

    @Override
    public void start() {
        String[] addressArrays = baseUrl.split(IpUtil.MARK);
        this.pingThreads = new Thread[addressArrays.length];
        for (int i = 0; i < this.pingThreads.length; i++) {
            int finalI = i;
            Thread pingThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (!started) {
                        RpcPing rpcPing = new RpcPing(System.currentTimeMillis(), IpUtil.getIp() + IpUtil.PREF + port, IpUtil.getIp(), port);
                        handlerHTTP(HTTP + addressArrays[finalI] + Ping, rpcPing);
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                        }
                    }
                }
            });
            pingThread.setName("pingThread-" + i);
            pingThread.setDaemon(true);
            pingThread.start();
            this.pingThreads[i] = pingThread;
        }
        logger.warning(">>>>>>>>> pingThread started >>>>>>>>>");
    }

    @Override
    public void stop() {
        for (Thread thread : this.pingThreads) {
            thread.interrupt();
        }
        if (!this.executorService.isShutdown()) {
            this.executorService.shutdown();
        }
    }

    @Override
    public RpcResponse handler(RpcRequest rpcRequest) {
        RpcResponse rpcResponse = new RpcResponse();
        try {
            Future<RpcResponse> responseFuture = this.executorService.submit(new Callable<RpcResponse>() {
                @Override
                public RpcResponse call() throws Exception {
                    RpcResponse rpcResponse = new RpcResponse(rpcRequest);
                    try {
                        Class<?> clazz = Class.forName(rpcRequest.getClassName());
                        Object bean = SpringUtil.getBeanByType(clazz);
                        if (bean instanceof IHandler) {
                            ((IHandler) bean).handler(rpcRequest);
                            rpcResponse.setSuccess(Boolean.TRUE);
                        }
                    } catch (Exception e) {
                        rpcResponse.setSuccess(Boolean.FALSE);
                        rpcResponse.setErrInfo(e.getMessage());
                    }
                    rpcResponse.getRpcRequest().setEndTime(System.currentTimeMillis());
                    return rpcResponse;
                }
            });
            rpcResponse = responseFuture.get(FIXED_TIME, TimeUnit.SECONDS);
        } catch (Exception e) {
            rpcResponse.setSuccess(Boolean.FALSE);
            rpcResponse.setErrInfo(e.getMessage());
        }
        return rpcResponse;
    }
}
